/*!
    \file    link32fa016bx_rcu.c
    \brief   RCU driver

    \version 2019-6-5, V1.0.0, firmware for LINK32FA016BX
*/

#include "link32fa016bx_rcu.h"


/*!
    \brief      deinitialize the RCU
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_deinit(void)
{
    /* enable HSI8M */
    RCU_CTL |= RCU_CTL_HSI_ON;
    rcu_osci_rdy_wait(RCU_HSI8M);

    /* reset CFG0 register */
    RCU_CFG0 &= ~(RCU_CFG0_SW  | RCU_CFG0_HPRE | RCU_CFG0_PPRE |
                  RCU_CFG0_PLL_SRC  | RCU_CFG0_PLL_MUL | RCU_CFG0_MCO);
    /* reset CTL register */
    RCU_CTL &= ~(RCU_CTL_HSE_ON | RCU_CTL_CSS_ON | RCU_CTL_PLL_ON);
    RCU_CTL &= ~RCU_CTL_HSE_BYP;
    /* reset INT and CFG1 register */
    //RCU_INT = 0x00ff0000U;
    RCU_CFG1 &= ~RCU_CFG1_PREDIV;
}

/*!
    \brief      enable the peripherals clock
    \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_CLKON_GPIOX X=[0-3] GPIO 0-3 clock
      \arg        RCU_CLKON_SDIO SDIO clock
      \arg        RCU_CLKON_USB USB clock
      \arg        RCU_CLKON_CRC CRC clock
      \arg        RCU_CLKON_FMC FMC clock
      \arg        RCU_CLKON_DEBUG DEBUG clock
      \arg        RCU_CLKON_CLINT CLINT clock
      \arg        RCU_CLKON_PLIC PLIC clock
      \arg        RCU_CLKON_UARTX UARTX clock
      \arg        RCU_CLKON_SYSCFG SysCfg clock
      \arg        RCU_CLKON_PMU  PMU clock
      \arg        RCU_CLKON_WWDG WWDG clock
      \arg        RCU_CLKON_PWMX X=[0-1] PWM 0-1 clock
      \arg        RCU_CLKON_SPIHX X=[0-1] SPI Host 0-1 clock
      \arg        RCU_CLKON_I2CX X=[0-1] I2C 0-1 clock
      \arg        RCU_CLKON_UARTX X=[0-1] UART 0-1 clock
      \arg        RCU_CLKON_SPIDX X=[0-1] SPI Device 0-1 clock
      \arg        RCU_CLKON_DMA DMA clock
      \arg        RCU_CLKON_ADCX X=[0-7] ADC 0-7 clock
    \param[out] none
    \retval     none
*/
void rcu_periph_clock_enable(rcu_periph_enum periph)
{
    RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
}

/*!
    \brief      disable the peripherals clock
    \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_CLKON_GPIOX X=[0-3] GPIO 0-3 clock
      \arg        RCU_CLKON_SDIO SDIO clock
      \arg        RCU_CLKON_USB USB clock
      \arg        RCU_CLKON_CRC CRC clock
      \arg        RCU_CLKON_FMC FMC clock
      \arg        RCU_CLKON_DEBUG DEBUG clock
      \arg        RCU_CLKON_CLINT CLINT clock
      \arg        RCU_CLKON_PLIC PLIC clock
      \arg        RCU_CLKON_UARTX UARTX clock
      \arg        RCU_CLKON_SYSCFG SysCfg clock
      \arg        RCU_CLKON_PMU  PMU clock
      \arg        RCU_CLKON_WWDG WWDG clock
      \arg        RCU_CLKON_PWMX X=[0-1] PWM 0-1 clock
      \arg        RCU_CLKON_SPIHX X=[0-1] SPI Host 0-1 clock
      \arg        RCU_CLKON_I2CX X=[0-1] I2C 0-1 clock
      \arg        RCU_CLKON_UARTX X=[0-1] UART 0-1 clock
      \arg        RCU_CLKON_SPIDX X=[0-1] SPI Device 0-1 clock
      \arg        RCU_CLKON_DMA DMA clock
      \arg        RCU_CLKON_ADCX X=[0-7] ADC 0-7 clock
    \param[out] none
    \retval     none
*/
void rcu_periph_clock_disable(rcu_periph_enum periph)
{
    RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
}


/*!
    \brief      reset the peripherals
    \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_RST_GPIOX X=[0-3] GPIO 0-3 reset
      \arg        RCU_RST_SDIO SDIO reset
      \arg        RCU_RST_USB USB reset
      \arg        RCU_RST_CRC CRC reset
      \arg        RCU_RST_FMC FMC reset
      \arg        RCU_RST_DEBUG DEBUG reset
      \arg        RCU_RST_CLINT CLINT reset
      \arg        RCU_RST_PLIC PLIC reset
      \arg        RCU_RST_UARTX UARTX reset
      \arg        RCU_RST_SYSCFG SysCfg reset
      \arg        RCU_RST_PMU  PMU reset
      \arg        RCU_RST_WWDG WWDG reset
      \arg        RCU_RST_PWMX X=[0-1] PWM 0-1 reset
      \arg        RCU_RST_SPIHX X=[0-1] SPI Host 0-1 reset
      \arg        RCU_RST_I2CX X=[0-1] I2C 0-1 reset
      \arg        RCU_RST_UARTX X=[0-1] UART 0-1 reset
      \arg        RCU_RST_SPIDX X=[0-1] SPI Device 0-1 reset
      \arg        RCU_RST_DMA DMA reset
      \arg        RCU_RST_ADCX X=[0-7] ADC 0-7 reset
    \param[out] none
    \retval     none
*/
void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
{
    RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
}

/*!
    \brief      disable reset the peripheral
    \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_RST_GPIOX X=[0-3] GPIO 0-3 reset
      \arg        RCU_RST_SDIO SDIO reset
      \arg        RCU_RST_USB USB reset
      \arg        RCU_RST_CRC CRC reset
      \arg        RCU_RST_FMC FMC reset
      \arg        RCU_RST_DEBUG DEBUG reset
      \arg        RCU_RST_CLINT CLINT reset
      \arg        RCU_RST_PLIC PLIC reset
      \arg        RCU_RST_UARTX UARTX reset
      \arg        RCU_RST_SYSCFG SysCfg reset
      \arg        RCU_RST_PMU  PMU reset
      \arg        RCU_RST_WWDG WWDG reset
      \arg        RCU_RST_PWMX X=[0-1] PWM 0-1 reset
      \arg        RCU_RST_SPIHX X=[0-1] SPI Host 0-1 reset
      \arg        RCU_RST_I2CX X=[0-1] I2C 0-1 reset
      \arg        RCU_RST_UARTX X=[0-1] UART 0-1 reset
      \arg        RCU_RST_SPIDX X=[0-1] SPI Device 0-1 reset
      \arg        RCU_RST_DMA DMA reset
      \arg        RCU_RST_ADCX X=[0-7] ADC 0-7 reset
    \param[out] none
    \retval     none
*/
void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
{
    RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
}

/*!
    \brief      reset the BKP domain
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_bkp_reset_enable(void)
{
    RCU_BDCTL |= RCU_BDCTL_BD_RST;
}

/*!
    \brief      disable the BKP domain reset
    \param[in]  none
    \param[out] none
    \retval     none
*/
void rcu_bkp_reset_disable(void)
{
    RCU_BDCTL &= ~RCU_BDCTL_BD_RST;
}

/*!
    \brief      configure the root clock source
    \param[in]  ck_sys: root clock source select
                only one parameter can be selected which is shown as below:
      \arg        RCU_SW_HSI8M: select CK_HSI8M as the CK_ROOT source
      \arg        RCU_SW_HSE  : select CK_HSE as the CK_ROOT source
      \arg        RCU_SW_PLL  : select CK_PLL as the CK_ROOT source
    \param[out] none
    \retval     none
*/
void rcu_root_clock_source_config(uint32_t ck_sys)
{
    uint32_t reg;

    reg = RCU_CFG0;
    /* reset the SW bits and set according to ck_sys */
    reg &= ~RCU_CFG0_SW;
    RCU_CFG0 = (reg | ck_sys);
}

/*!
    \brief      get the system clock source
    \param[in]  none
    \param[out] none
    \retval     which clock is selected as CK_SYS source
      \arg        RCU_SWS_HSI8M: CK_IRC8M is selected as the CK_ROOT source
      \arg        RCU_SWS_HSE  : CK_HSE is selected as the CK_ROOT source
      \arg        RCU_SWS_PLL  : CK_PLL is selected as the CK_ROOT source
*/
uint32_t rcu_root_clock_source_get(void)
{
    return (RCU_CFG0 & RCU_CFG0_SWS);
}

/*!
    \brief      configure the AHB clock prescaler selection
    \param[in]  ck_ahb: AHB clock prescaler selection
                only one parameter can be selected which is shown as below:
      \arg        RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
    \param[out] none
    \retval     none
*/
void rcu_ahb_clock_config(uint32_t ck_ahb)
{
    uint32_t reg;

    reg = RCU_CFG0;

    /* reset the AHBPSC bits and set according to ck_ahb */
    reg &= ~RCU_CFG0_HPRE;
    RCU_CFG0 = (reg | ck_ahb);
}

/*!
    \brief      configure the APB1 clock prescaler selection
    \param[in]  ck_apb1: APB1 clock prescaler selection
                only one parameter can be selected which is shown as below:
      \arg        RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
      \arg        RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
      \arg        RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
      \arg        RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
      \arg        RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
    \param[out] none
    \retval     none
*/
void rcu_apb_clock_config(uint32_t ck_apb1)
{
    uint32_t reg;

    reg = RCU_CFG0;

    /* reset the APB1PSC and set according to ck_apb1 */
    reg &= ~RCU_CFG0_PPRE;
    RCU_CFG0 = (reg | ck_apb1);
}


/*!
    \brief      configure the CK_OUT0 clock source
    \param[in]  ckout0_src: CK_OUT0 clock source selection
                only one parameter can be selected which is shown as below:
      \arg        RCU_CKOUT0SRC_NONE: no clock selected
      \arg        RCU_CKOUT0SRC_CKSYS: system clock selected
      \arg        RCU_CKOUT0SRC_IRC8M: high speed 8M internal oscillator clock selected
      \arg        RCU_CKOUT0SRC_HSE: HSE selected
      \arg        RCU_CKOUT0SRC_CKPLL_DIV2: CK_PLL/2 selected
      \arg        RCU_CKOUT0SRC_CKPLL1: CK_PLL1 selected
      \arg        RCU_CKOUT0SRC_CKPLL2_DIV2: CK_PLL2/2 selected
      \arg        RCU_CKOUT0SRC_EXT1: EXT1 selected
      \arg        RCU_CKOUT0SRC_CKPLL2: PLL2 selected
    \param[out] none
    \retval     none
*/
//void rcu_ckout0_config(uint32_t ckout0_src)
//{
//    uint32_t reg;
//
//    reg = RCU_CFG0;
//
//    /* reset the CKOUT0SRC, set according to ckout0_src */
//    reg &= ~RCU_CFG0_CKOUT0SEL;
//    RCU_CFG0 = (reg | ckout0_src);
//}

/*!
    \brief      configure the main PLL clock
    \param[in]  pll_src: PLL clock source selection
                only one parameter can be selected which is shown as below:
      \arg        RCU_PLL_SRC_HSI8M_D2: HSI8M/2 clock selected as source clock of PLL
      \arg        RCU_PLL_SRC_HSE: HSE selected as source clock of PLL
    \param[in]  pll_mul: PLL clock multiplication factor
                only one parameter can be selected which is shown as below:
      \arg        RCU_PLL_MULx (x = 2,3,...,16)
    \param[out] none
    \retval     none
*/
void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul)
{
    uint32_t reg = 0U;

    reg = RCU_CFG0;

    /* PLL clock source and multiplication factor configuration */
    reg &= ~(RCU_CFG0_PLL_SRC | RCU_CFG0_PLL_MUL);
    reg |= (pll_src | pll_mul);

    RCU_CFG0 = reg;
}


/*!
    \brief      configure the RTC clock source selection
    \param[in]  rtc_clock_source: RTC clock source selection
                only one parameter can be selected which is shown as below:
      \arg        RCU_RTC_SRC_NONE: no clock selected
      \arg        RCU_RTC_SRC_LSE  : CK_LSE   selected as RTC source clock
      \arg        RCU_RTC_SRC_LSI40K: CK_IRC40K selected as RTC source clock
      \arg        RCU_RTC_SRC_HSE_D32: CK_HSE/32 selected as RTC source clock
    \param[out] none
    \retval     none
*/
void rcu_rtc_clock_config(uint32_t rtc_clock_source)
{
    uint32_t reg;

    reg = RCU_BDCTL;
    /* reset the RTCSRC bits and set according to rtc_clock_source */
    reg &= ~RCU_BDCTL_RTC_SEL;
    RCU_BDCTL = (reg | rtc_clock_source);
}


/*!
    \brief      get the clock stabilization and periphral reset flags
    \param[in]  flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_FLAG_HSI8M_RDY: HSI8M ready flag
      \arg        RCU_FLAG_HSE_RDY: HSE ready flag
      \arg        RCU_FLAG_PLL_RDY: PLL ready flag
      \arg        RCU_FLAG_LSE_RDY: LSE ready flag
      \arg        RCU_FLAG_LSI40K_RDY: LSI40K ready flag
    \param[out] none
    \retval     FlagStatus: SET or RESET
*/
FlagStatus rcu_flag_get(rcu_flag_enum flag)
{
    /* get the rcu flag */
    if (RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))) {
        return SET;
    } else {
        return RESET;
    }
}


/*!
    \brief      wait for oscillator stabilization flags is SET or oscillator startup is timeout
    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_HSE  : high speed crystal oscillator(HSE)
      \arg        RCU_LSE  : low speed crystal oscillator(LSE)
      \arg        RCU_HSI8M: internal 8M RC oscillators(HSI8M)
      \arg        RCU_LSI40K: internal 40K RC oscillator(LSI40K)
      \arg        RCU_PLL: phase locked loop(PLL)
    \param[out] none
    \retval     ErrStatus: SUCCESS or ERROR
*/
ErrStatus rcu_osci_rdy_wait(rcu_osci_type_enum osci)
{
    uint32_t stb_cnt = 0U;
    ErrStatus reval = ERROR;
    FlagStatus osci_stat = RESET;

    switch (osci) {
        /* wait HSE ready */
        case RCU_HSE:
            while ((RESET == osci_stat) && (HSE_STARTUP_TIMEOUT != stb_cnt)) {
                osci_stat = rcu_flag_get(RCU_FLAG_HSE_RDY);
                stb_cnt++;
            }

            /* check whether flag is set or not */
            if (RESET != rcu_flag_get(RCU_FLAG_HSE_RDY)) {
                reval = SUCCESS;
            }
            break;

        /* wait LSE ready */
        case RCU_LSE:
            while ((RESET == osci_stat) && (LSE_STARTUP_TIMEOUT != stb_cnt)) {
                osci_stat = rcu_flag_get(RCU_FLAG_LSE_RDY);
                stb_cnt++;
            }

            /* check whether flag is set or not */
            if (RESET != rcu_flag_get(RCU_FLAG_LSE_RDY)) {
                reval = SUCCESS;
            }
            break;

        /* wait HSI8M ready */
        case RCU_HSI8M:
            while ((RESET == osci_stat) && (HSI8M_STARTUP_TIMEOUT != stb_cnt)) {
                osci_stat = rcu_flag_get(RCU_FLAG_HSI8M_RDY);
                stb_cnt++;
            }

            /* check whether flag is set or not */
            if (RESET != rcu_flag_get(RCU_FLAG_HSI8M_RDY)) {
                reval = SUCCESS;
            }
            break;

        /* wait LSI40K ready */
        case RCU_LSI40K:
            while ((RESET == osci_stat) && (LSI40K_STARTUP_TIMEOUT != stb_cnt)) {
                osci_stat = rcu_flag_get(RCU_FLAG_LSI40K_RDY);
                stb_cnt++;
            }

            /* check whether flag is set or not */
            if (RESET != rcu_flag_get(RCU_FLAG_LSI40K_RDY)) {
                reval = SUCCESS;
            }
            break;

        /* wait PLL ready */
        case RCU_PLL:
            while ((RESET == osci_stat) && (PLL_STARTUP_TIMEOUT != stb_cnt)) {
                osci_stat = rcu_flag_get(RCU_FLAG_PLL_RDY);
                stb_cnt++;
            }

            /* check whether flag is set or not */
            if (RESET != rcu_flag_get(RCU_FLAG_PLL_RDY)) {
                reval = SUCCESS;
            }
            break;
        default:
            break;
    }

    /* return value */
    return reval;
}

/*!
    \brief      turn on the oscillator
    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_HSE  : high speed crystal oscillator(HSE)
      \arg        RCU_LSE  : low speed crystal oscillator(LSE)
      \arg        RCU_HSI8M: internal 8M RC oscillators(HSI8M)
      \arg        RCU_LSI40K: internal 40K RC oscillator(LSI40K)
      \arg        RCU_PLL: phase locked loop(PLL)
    \param[out] none
    \retval     none
*/
void rcu_osci_on(rcu_osci_type_enum osci)
{
    RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
}

/*!
    \brief      turn off the oscillator
    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_HSE  : high speed crystal oscillator(HSE)
      \arg        RCU_LSE  : low speed crystal oscillator(LSE)
      \arg        RCU_HSI8M: internal 8M RC oscillators(HSI8M)
      \arg        RCU_LSI40K: internal 40K RC oscillator(LSI40K)
      \arg        RCU_PLL: phase locked loop(PLL)
    \param[out] none
    \retval     none
*/
void rcu_osci_off(rcu_osci_type_enum osci)
{
    RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
}

/*!
    \brief      enable the oscillator bypass mode, HSE_ON or LSE_ON must be reset before it
    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_HSE: high speed crystal oscillator(HSE)
      \arg        RCU_LSE: low speed crystal oscillator(LSE)
    \param[out] none
    \retval     none
*/
void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
{
    uint32_t reg;

    switch (osci) {
        /* enable HSE to bypass mode */
        case RCU_HSE:
            reg = RCU_CTL;
            //RCU_CTL &= ~RCU_CTL_HSE_ON;
            RCU_CTL = (reg | RCU_CTL_HSE_BYP);
            break;
        /* enable LSE to bypass mode */
        case RCU_LSE:
            reg = RCU_BDCTL;
            //RCU_BDCTL &= ~RCU_BDCTL_LSE_ON;
            RCU_BDCTL = (reg | RCU_BDCTL_LSE_BYP);
            break;
        case RCU_HSI8M:
        case RCU_LSI40K:
        case RCU_PLL:
            break;
        default:
            break;
    }
}

/*!
    \brief      disable the oscillator bypass mode, HSE_ON or LSE_ON must be reset before it
    \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
                only one parameter can be selected which is shown as below:
      \arg        RCU_HSE: high speed crystal oscillator(HSE)
      \arg        RCU_LSE: low speed crystal oscillator(LSE)
    \param[out] none
    \retval     none
*/
void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
{
    uint32_t reg;

    switch (osci) {
        /* disable HSE to bypass mode */
        case RCU_HSE:
            reg = RCU_CTL;
            RCU_CTL = (reg & ~RCU_CTL_HSE_BYP);
            break;
        /* disable LSE to bypass mode */
        case RCU_LSE:
            reg = RCU_BDCTL;
            RCU_BDCTL = (reg & ~RCU_BDCTL_LSE_BYP);
            break;
        case RCU_HSI8M:
        case RCU_LSI40K:
        case RCU_PLL:
            break;
        default:
            break;
    }
}


/*!
    \brief      set the HSI8M trim value
    \param[in]  hsi8m_adjval: HSI8M trim value, must be between 0 and 0x1F
    \param[out] none
    \retval     none
*/
void rcu_hsi8m_trim_set(uint32_t hsi8m_trim)
{
    uint32_t reg;

    reg = RCU_CTL;
    /* reset the IRC8M DJ bits and set according to hsi8m_trim */
    reg &= ~RCU_CTL_HSI_TRIM;
    RCU_CTL = (reg | ((hsi8m_trim & 0x1FU) << 3));
}


/*!
    \brief      get the system clock, bus and peripheral clock frequency
    \param[in]  clock: the clock frequency which to get
                only one parameter can be selected which is shown as below:
      \arg        CK_ROOT: root clock frequency
      \arg        CK_AHB: AHB clock frequency
      \arg        CK_APB: APB clock frequency
    \param[out] none
    \retval     clock frequency of root, AHB, APB
*/
uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
{
    uint32_t sws, ck_freq = 0U;
    uint32_t ckroot_freq, ahb_freq, apb_freq;
    //uint32_t pllsrc, prediv, pllmf, ck_src, idx, clk_exp;
    uint32_t idx, clk_exp;

    /* exponent of AHB, APB1 and APB2 clock divider */
    uint8_t ahb_pre[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
    uint8_t apb_pre[8] = {0, 0, 0, 0, 1, 2, 3, 4};

    sws = GET_BITS(RCU_CFG0, 2, 3);
    switch (sws) {
        /* IRC8M is selected as CK_SYS */
        case RCU_SW_HSI8M:
            ckroot_freq = HSI8M_FREQ;
            break;
        /* HSE is selected as CK_SYS */
        case RCU_SW_HSE:
            ckroot_freq = HSE_FREQ;
            break;
        /* PLL is selected as CK_SYS */
        case RCU_SW_PLL:
            /* PLL clock source selection, HSE or HSI8M/2 */
            //pllsrc = (RCU_CFG0 & RCU_CFG0_PLL_SRC);

            //if (RCU_PLL_SRC_HSE == pllsrc) {
            //    /* PLL clock source is HSE */
            //    ck_src = HSE_FREQ;
            //    prediv = (RCU_CFG1 & RCU_CFG1_PREDIV) + 1U;
            //    ck_src /= prediv;
            //} else {
            //    ck_src = HSI8M_FREQ / 2U;
            //}

            ///* PLL multiplication factor */
            //pllmf = GET_BITS(RCU_CFG0, 18, 21);
            //ckroot_freq = ck_src * pllmf;
	    ckroot_freq = 48000000;
            break;
        /* HSI8M is selected as CK_SYS */
        default:
            ckroot_freq = HSI8M_FREQ;
            break;
    }

    /* calculate AHB clock frequency */
    idx = GET_BITS(RCU_CFG0, 4, 7);
    clk_exp = ahb_pre[idx];
    ahb_freq = ckroot_freq >> clk_exp;

    /* calculate APB1 clock frequency */
    idx = GET_BITS(RCU_CFG0, 8, 10);
    clk_exp = apb_pre[idx];
    apb_freq = ahb_freq >> clk_exp;

    /* return the clocks frequency */
    switch (clock) {
        case CK_ROOT:
            ck_freq = ckroot_freq;
            break;
        case CK_AHB:
            ck_freq = ahb_freq;
            break;
        case CK_APB:
            ck_freq = apb_freq;
            break;
        default:
	    ck_freq = ckroot_freq;
            break;
    }
    return ck_freq;
}
